#define NOMINMAX
#include "BestPriceFormat.h"

#include <bondlib/BondCDCPriceInfo.h>
#include <bondlib/BondCalendar.h>
#include <bondlib/BondContainer.h>
#include <core/time/system_time.h>
#include <qbtools/tools.h>
#include <uam/UserAccountManager.h>

#include "../Detail/BondDetailData.h"

QString MakeDateFormat(const ::base::CTime& tmBiz,
                       const qb::base::CTime& tmNow) {
  QString strTime;
  if (tmBiz == qb::base::CTime(0)) {
    return "--";
  }
  if (tmBiz.GetYear() != tmNow.GetYear() ||
      tmBiz.GetMonth() != tmNow.GetMonth() ||
      tmBiz.GetDay() != tmNow.GetDay()) {
    strTime = QString("%1/%2/%3 %4:%5:%6")
                  .arg(tmBiz.GetYear(), 4, 10, QLatin1Char('0'))
                  .arg(tmBiz.GetMonth(), 2, 10, QLatin1Char('0'))
                  .arg(tmBiz.GetDay(), 2, 10, QLatin1Char('0'))
                  .arg(tmBiz.GetHour(), 2, 10, QLatin1Char('0'))
                  .arg(tmBiz.GetMinute(), 2, 10, QLatin1Char('0'))
                  .arg(tmBiz.GetSecond(), 2, 10, QLatin1Char('0'));
  } else {
    strTime = QString("%1:%2:%3")
                  .arg(tmBiz.GetHour(), 2, 10, QLatin1Char('0'))
                  .arg(tmBiz.GetMinute(), 2, 10, QLatin1Char('0'))
                  .arg(tmBiz.GetSecond(), 2, 10, QLatin1Char('0'));
  }

  return strTime;
}

QString GetDirection(int type) {
  QString strDir = "";
  switch (type) {
    case givenType:
      strDir = "GVN";
      break;
    case tokenType:
      strDir = "TKN";
      break;
    case tradeType:
      strDir = "TRD";
      break;
  }
  return strDir;
}

int MakeTypeOperate(int type, int operate) {
  if (type == 1) return FORMAT_TYPE::changeType;
  if (type == 2) {
    if (operate == 0)
      return FORMAT_TYPE::tokenType;
    else if (operate == 1)
      return FORMAT_TYPE::givenType;
    else if (operate == 2)
      return FORMAT_TYPE::tradeType;
  }
  return -1;
}

void GetStarFlag(IN char* flagBargain, OUT QString& flag) {
  int nUpon = 0;
  if (strcmp(flagBargain, "2") == 0)
    nUpon = 2;
  else if (strcmp(flagBargain, "1") == 0 || strcmp(flagBargain, "true") == 0)
    nUpon = 1;
  else
    nUpon = 0;

  if (nUpon == 1)
    flag = "*";
  else if (nUpon == 2)
    flag = "**";
  else
    flag = "";
  return;
}

void FormatPriceToClipBoardV2(const char* brokerID, QString strKey,
                              QString& source, time_t curTime,
                              bool bAddCorpFlag, bool eng) {
  log_begin();
  if (!brokerID) return;

  QString strPrice;
  QString strVol = "";

  time_t tmBiz2 = 0;
  GetBestPriceByKeyNew(strKey, brokerID, strPrice, strVol, tmBiz2);

  source = GetBestFormat(strKey, curTime, strPrice, strVol, brokerID,
                         bAddCorpFlag, tmBiz2, eng);

  log_end();
}

void GetBestPriceByKeyNew(QString strKey, const char* brokerID,
                          QString& strPrice, QString& strVol, time_t& tmBiz,
                          int nCleanSpeed) {
  REPORT report;
  memset(&report, 0, sizeof(REPORT));
  if (nCleanSpeed > 0) {
    BYTE btSett;
    switch (nCleanSpeed) {
      case 1:
        btSett = 0x1;
        break;
      case 2:
        btSett = 0x2;
        break;
      case 3:
        btSett = 0x4;
        break;
      case 4:
        btSett = 0x3;
        break;
      default:
        btSett = 0x0;
        break;
    }
    CBondContainer::instance().GetCompanyRepByKeyAndSettlement(
        strKey.toLocal8Bit(), brokerID, btSett, report);
  } else
    CBondContainer::instance().GetCompanyRepByKey(strKey.toLocal8Bit(),
                                                  brokerID, report);

  QString strTemp;
  QString strBidPrice, strBidStar, strBidCount;
  QString strOfrPrice, strOfrStar, strOfrCount;

  tmBiz = std::max(report.m_time, report.m_create_time);
  PRICE* pBid = &(report.m_bidinfo);
  PRICE* pOfr = &(report.m_askinfo);

  GetStarFlag(pOfr->m_flag_bargain, strOfrStar);

  strBidCount = SSTools::StringRemoveZero(pBid->m_sVolume);
  strOfrCount = SSTools::StringRemoveZero(pOfr->m_sVolume);

  if (strcmp(pBid->m_price_status, "0") == 0) {
    strBidPrice = "--";
    strBidStar = "";
    strBidCount = "--";
  } else {
    strBidPrice = SSTools::FormatePrice(pBid->m_sPrice);
    if (strBidPrice.length() <= 0) strBidPrice = "--";

    GetStarFlag(pBid->m_flag_bargain, strBidStar);

    if (strlen(pBid->m_description) > 0)
      strBidCount = QString::fromLocal8Bit(pBid->m_description);
    else
      strBidCount = SSTools::StringRemoveZero(pBid->m_sVolume);
  }

  if (strcmp(pOfr->m_price_status, "0") == 0) {
    strOfrPrice = "--";
    strOfrStar = "";
    strOfrCount = "--";
  } else {
    strOfrPrice = SSTools::FormatePrice(pOfr->m_sPrice);
    if (strOfrPrice.length() <= 0) strOfrPrice = "--";

    GetStarFlag(pOfr->m_flag_bargain, strOfrStar);

    if (strlen(pOfr->m_description) > 0)
      strOfrCount = QString::fromLocal8Bit(pOfr->m_description);
    else
      strOfrCount = SSTools::StringRemoveZero(pOfr->m_sVolume);
  }

  strPrice = QString("%1%2/%3%4")
                 .arg(strBidPrice, strBidStar, strOfrPrice, strOfrStar);
  strVol = QString("%1/%2").arg(strBidCount, strOfrCount);

  return;
}

QString GetBestFormat(QString strCombBondKey, time_t curTime, QString strPrice,
                      QString strVol, const char* brokerID, bool bAddCorpFlag,
                      time_t tmBiz, bool eng) {
  QString strRemainMaturity, strShortName, strCode,
      strExType = "", strCDCValue = "", strLevel, source = "", strPledge = "";

  int nBondIndex =
      CBondContainer::instance().GetBondIndex(strCombBondKey.toStdString());
  const CBondInfo& bondInfo = CBondContainer::instance().ElementAtR(nBondIndex);

  strShortName = QString("%1   ").arg(QString::fromLocal8Bit(
      eng ? bondInfo.GetBondShortNameEn().c_str()
          : bondInfo.GetBondShortName()));  // pList->GetItemText(nRow,3);
  strCode = QString("%1").arg(QString::fromLocal8Bit(
      bondInfo.GetCombBondCode()));  // = pList->GetItemText(nRow,2);

  strRemainMaturity =
      QString("%1").arg(QString::fromLocal8Bit(bondInfo.GetRemainPeriod(
          curTime)));  //.Format(_T("%s"),
                       //SSA2W(bondInfo.GetBondCode()));//pList->GetItemText(nRow,1);
  if (strRemainMaturity.isEmpty()) strRemainMaturity = "--";

  strRemainMaturity += BuildHoliday(bondInfo, curTime, eng);
  if (eng && strRemainMaturity == "已到期") {
    strRemainMaturity = "Expired";
  }

  if (strcmp(bondInfo.GetBondSubType(), "LLB") == 0 &&
      strcmp(bondInfo.GetEntCor(), "SMB") == 0) {
    strExType = eng ? "General Purpose" : "一般债";  // 一般债
  } else if (strcmp(bondInfo.GetBondSubType(), "LLB") == 0 &&
             strcmp(bondInfo.GetEntCor(), "NMB") == 0) {
    strExType = eng ? "Special Purpose" : "专项债";  // 专项债
  } else if (!bondInfo.IsRatingDebt() &&
             qstricmp(bondInfo.GetAssetStatus(), "PRI") != 0 &&
             qstricmp(bondInfo.GetAssetStatus(), "PUB") != 0) {
    strExType = eng ? "Public" : "公募";  // 公募
  } else if (qstricmp(bondInfo.GetAssetStatus(), "PUB") == 0) {
    strExType = eng ? "Qualified" : "小公募";  // 小公募
  } else if (qstricmp(bondInfo.GetAssetStatus(), "PRI") == 0) {
    strExType = eng ? "Placement" : "私募";  // 私募
  }
  if (!strExType.isEmpty()) strExType += "   ";

  bool bIsCDCAuthValid = bondInfo.IsCDCAuthValid();
  if (bIsCDCAuthValid) {
    int nOptType = CBondCDCPriceInfo::est_type_invalid;
    std::string cdc =
        CBondCDCPriceInfo::instance()
            .GetCDCPriceYesterday(nOptType, bIsCDCAuthValid, nBondIndex,
                                  CBondCDCPriceInfo::price_type_yield, false)
            .c_str();
    QString strOption;
    switch (nOptType + 1) {
      case 0: {
        strOption = (eng ? "YTE/YTM" : "行权/到期");
      } break;
      case 1: {
        strOption = (eng ? "YTE" : "行权");
      } break;
      case 2: {
        strOption = (eng ? "YTM" : "到期");
      } break;
      case 3: {
        strOption = (eng ? "" : "");
      } break;
      case 4: {
        strOption = (eng ? "/" : "/");
      } break;
      default:
        break;
    }
    if (!cdc.empty())
      strCDCValue = QString("%1 %2")
                        .arg(eng ? "Prev.CDC" : "昨日中债")
                        .arg(QString::fromStdString(cdc));
    else
      strCDCValue = QString("%1 --").arg(eng ? "Prev.CDC" : "昨日中债");

    if (!strOption.isEmpty()) {
      strCDCValue += (" " + strOption);
    }
  }

  strLevel = QString::fromLocal8Bit(
      bondInfo
          .GetIssuerBondRating());  // 与DlgQuoteV2.cpp中的case COL_RATE:处一致
  if (!strLevel.isEmpty()) strLevel += "   ";

  QString strOther = "";
  if (strcmp(bondInfo.GetRateType(), "FIXED") != 0)
    strOther =
        QString("%1   ").arg(QString::fromLocal8Bit(bondInfo.GetRateType()));

  QString strRemainMaturityCode = strRemainMaturity + "   ";
  if (!strCode.isEmpty())
    strRemainMaturityCode += strCode + "   ";  // 如果代码为空 ；

  QString strCorpName = "";
  if (bAddCorpFlag) {
    char szCorp[64] = {0};
    int nID;
    if (VERIRY_IS_CFETST_BROKER_STRING(brokerID)) {
      nID = NEW_DETAIL_CFETS_BROKER;
    } else if (VERIRY_IS_EXCHANGE_BROKER_STRING(brokerID)) {
      nID = NEW_DETAIL_EXCHANGE_BROKER;
    } else {
      nID = atoi(brokerID);
    }

    SSUserAccountManager::instance().GetBrokerNameByID(nID, szCorp, 64,
                                                       (eng ? "EN" : "CHS"));
    strCorpName = QString::fromLocal8Bit(szCorp);
  }

  QString strFrnMark = BuildFrnMark(bondInfo);
  if (!strFrnMark.isEmpty()) strFrnMark += "   ";

  strPledge = QString::fromLocal8Bit(bondInfo.GetConversionRate());
  /*if (strPledge.length() > 0)
  {
          QString pledge = QString("%1%2%3%4")
                  .arg("   ")
                  .arg(eng ? "Pledge ratio":"质押比")
                  .arg(" ")
                  .arg(strPledge.data());
          strPledge = pledge;
  }*/

  if (strPledge.length() > 0) {
    strPledge = QString("%1%2%3%4")
                    .arg("   ")
                    .arg(eng ? "Pledge ratio" : ("质押比"))
                    .arg(" ")
                    .arg(strPledge);
  }
  source = QString("%1%2%3%4   %5   %6%7%8%9   %10%11")
               .arg(strRemainMaturityCode)
               .arg(strShortName)
               .arg(strExType)
               .arg(strPrice)
               .arg(strVol)
               .arg(strLevel)
               .arg(strFrnMark)
               .arg(strOther)
               .arg(strCorpName)
               .arg(strCDCValue)
               .arg(strPledge);

  if (tmBiz != 0) {
    source += "   ";
    source += MakeDateFormat(qb::base::CTime(tmBiz), qb::base::CTime(curTime));
  }

  source += "\n";

  return source;
}

QString BuildHoliday(const CBondInfo& bi, const time_t tNow, bool eng) {
  bool isCIB = true;
  int nDayCIB = 0, nDaySSE = 0;

  QString strRet;

  if (CBondCalendar::instance().IsHoliday_CHY_Time(bi, tNow, isCIB, nDayCIB,
                                                   nDaySSE)) {
    QString szFormat;
    if (!isCIB) {
      szFormat = eng ? "(HD %1)" : "(休%1)";
      strRet = QString(szFormat).arg(nDaySSE);
    } else {
      if (nDayCIB == nDaySSE) {
        szFormat = eng ? "(HD %1)" : "(休%1)";
        strRet = QString(szFormat).arg(nDayCIB);
      } else {
        szFormat = eng ? "(HD %1/%2)" : "(休%1/%2)";
        strRet = QString(szFormat).arg(nDayCIB, nDaySSE);
      }
    }
  }

  return strRet;
}

QString BuildFrnMark(const CBondInfo& bi) {
  QString strRet;
  if (strcmp("FRN", bi.GetCouponType()) == 0 &&
      atoi(bi.GetMaturityDate()) > 0 &&
      atoi(bi.GetMaturityDate()) == atoi(bi.GetNextCoupon_Date())) {
    QString strTmp = QString::fromLocal8Bit(bi.GetFRNIndexID());
    strTmp = strTmp.toUpper();

    if (strTmp.indexOf("SHIBOR") != -1) {
      strRet = "原SHIBOR";
    } else if (strTmp.indexOf("DEPO") != -1) {
      strRet = "原DEPO";
    }
  }

  return strRet;
}

void FormatDealToClipBoard(const char* brokerID, QString strKey,
                           QString& source, time_t curTime,
                           const MarketStreamInfo& unit, bool bAddCorpFlag,
                           bool eng) {
  if (!brokerID) return;
  if (atoi(unit.m_type) == 2) {  // 成交
    QString strTemp, strPrice, strDirection, strTime;
    char cPrice[64] = {0};
    // char cVolumn[33]={0};
    FIELDCOPY(cPrice, unit.m_body.m_price);
    // FIELDCOPY(cVolumn,unit.m_body2.m_volume);
    strPrice = "--";
    if (cPrice[0] != '\0') strPrice = SSTools::FormatePrice(cPrice);

    int m_type = MakeTypeOperate(2, atoi(unit.m_operate));
    strDirection = GetDirection(m_type);
    qb::base::CTime ctm(std::max(unit.m_modify_time, unit.m_create_time));
    if (std::max(unit.m_modify_time, unit.m_create_time) != 0) {
      strTime = QString("%1:%2:%3")
                    .arg(ctm.GetHour(), 2, 10, QLatin1Char('0'))
                    .arg(ctm.GetMinute(), 2, 10, QLatin1Char('0'))
                    .arg(ctm.GetSecond(), 2, 10, QLatin1Char('0'));
    }

    FormatDoneToClipBoard(brokerID, strDirection, strKey, strTemp, curTime,
                          strPrice, strTime, bAddCorpFlag, eng);
    source = strTemp;
  }
}

void FormatDoneToClipBoard(const char* brokerID, QString direction,
                           QString strComBondKey, QString& source,
                           time_t curTime, QString price, QString DoneTime,
                           bool bAddCorpFlag, bool eng, QString strCdcResult) {
  log_begin();
  if (!brokerID) return;

  REPORT report;
  memset(&report, 0, sizeof(REPORT));

  int nBondIndex =
      CBondContainer::instance().GetBondIndex(strComBondKey.toStdString());
  const CBondInfo& bondInfo = CBondContainer::instance().ElementAtR(nBondIndex);

  QString strRemainMaturity, strCode, strShort, strExType = "";

  strRemainMaturity =
      QString("%1").arg(QString::fromLocal8Bit(bondInfo.GetRemainPeriod(
          curTime)));  //.Format(_T("%s"),
                       //SSA2W(bondInfo.GetBondCode()));//pList->GetItemText(nRow,1);
  if (strRemainMaturity.isEmpty()) strRemainMaturity = "--";
  strRemainMaturity += BuildHoliday(bondInfo, curTime, eng);

  strCode =
      QString("%1").arg(QString::fromLocal8Bit(bondInfo.GetCombBondCode()));
  if (strCode.isEmpty()) strCode = "--";

  strShort = QString("%1").arg(
      eng ? QString::fromLocal8Bit(bondInfo.GetBondShortNameEn().c_str())
          : QString::fromLocal8Bit(bondInfo.GetBondShortName()));
  if (strShort.isEmpty()) strShort = "--";

  if (strcmp(bondInfo.GetBondSubType(), "LLB") == 0 &&
      strcmp(bondInfo.GetEntCor(), "SMB") == 0) {
    strExType = eng ? "General Purpose" : "一般债";  // 一般债
  } else if (strcmp(bondInfo.GetBondSubType(), "LLB") == 0 &&
             strcmp(bondInfo.GetEntCor(), "NMB") == 0) {
    strExType = eng ? "Special Purpose" : "专项债";  // 专项债
  } else if (!bondInfo.IsRatingDebt() &&
             qstricmp(bondInfo.GetAssetStatus(), "PRI") != 0 &&
             qstricmp(bondInfo.GetAssetStatus(), "PUB") != 0) {
    strExType = eng ? "Public" : "公募";  // 公募
  } else if (qstricmp(bondInfo.GetAssetStatus(), "PUB") == 0) {
    strExType = eng ? "Qualified" : "小公募";  // 小公募
  } else if (qstricmp(bondInfo.GetAssetStatus(), "PRI") == 0) {
    strExType = eng ? "Placement" : "私募";  // 私募
  }

  QString strCDCValue = "";
  if (!strCdcResult.isEmpty()) {
    strCDCValue = strCdcResult;  // 由外部控制传入中债估值
  } else {
    bool bIsCDCAuthValid = bondInfo.IsCDCAuthValid();
    if (bIsCDCAuthValid) {
      int nOptType = CBondCDCPriceInfo::est_type_invalid;
      std::string scdc =
          CBondCDCPriceInfo::instance()
              .GetCDCPriceYesterday(nOptType, bIsCDCAuthValid, nBondIndex,
                                    CBondCDCPriceInfo::price_type_yield, false)
              .c_str();
      QString strOption;
      switch (nOptType + 1) {
        case 0: {
          strOption = (eng ? "YTE/YTM" : "行权/到期");
        }
        case 1: {
          strOption = (eng ? "YTE" : "行权");
        } break;
        case 2: {
          strOption = (eng ? "YTM" : "到期");
        } break;
        case 3: {
          strOption = (eng ? "" : "");
        } break;
        case 4: {
          strOption = (eng ? "/" : "/");
        } break;
        default:
          break;
      }
      strCDCValue = eng ? "Prev.CDC" : "昨日中债";
      strCDCValue += " ";
      if (!scdc.empty())
        strCDCValue += QString::fromLocal8Bit(scdc.c_str());
      else
        strCDCValue += "--";

      if (!strOption.isEmpty()) {
        strCDCValue += (" " + strOption);
      }
    }
  }

  QString strRate = QString::fromLocal8Bit(bondInfo.GetIssuerBondRating());

  QString strCouponType = QString::fromLocal8Bit(bondInfo.GetRateType());
  if (strCouponType == "FIXED") strCouponType.clear();

  QString strFrnMark = BuildFrnMark(bondInfo);

  source = strRemainMaturity;
  if (!strCode.isEmpty()) source += "   " + strCode;

  if (!strShort.isEmpty()) source += "   " + strShort;

  if (!strExType.isEmpty()) source += "   " + strExType;

  if (!price.isEmpty()) source += "   " + price;

  if (!direction.isEmpty()) source += "   " + direction;

  if (!strRate.isEmpty()) source += "   " + strRate;

  if (!strCouponType.isEmpty()) source += "   " + strCouponType;
  if (!strFrnMark.isEmpty()) source += "   " + strFrnMark;

  if (bAddCorpFlag) {
    char szCorp[64] = {0};
    int nID;
    if (VERIRY_IS_CFETST_BROKER_STRING(brokerID)) {
      nID = NEW_DETAIL_CFETS_BROKER;
    } else if (VERIRY_IS_EXCHANGE_BROKER_STRING(brokerID)) {
      nID = NEW_DETAIL_EXCHANGE_BROKER;
    } else {
      nID = atoi(brokerID);
    }

    SSUserAccountManager::instance().GetBrokerNameByID(nID, szCorp, 64,
                                                       (eng ? "EN" : "CHS"));
    if (strlen(szCorp) > 0) source += "   " + QString::fromLocal8Bit(szCorp);
  }

  if (!strCDCValue.isEmpty()) source += "   " + strCDCValue;

  if (!DoneTime.isEmpty()) {
    source += "   " + DoneTime;
  }

  source += "\n";
  log_end();
}
